package cn.mw.cmdb.util;

import cn.mw.cmdb.entity.AssetsInterfaceDTO;
import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.exception.DataUniqueException;
import cn.mw.cmdb.mongoMapper.AssetsInterfaceMapper;
import cn.mw.cmdb.mongoMapper.InstanceInfoMapper;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.view.TreeViewObject;
import cn.mw.microMonitorCommon.api.cmdb.TreeView;
import cn.mw.microMonitorCommon.api.common.MwEngineManageService;
import cn.mw.microMonitorCommon.entity.common.MwTPServerTable;
import cn.mw.scanengine.service.ScanEngineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.text.Collator;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.mw.cmdb.util.ValConvertUtil.doubleValueConvert;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;
@Slf4j
public class CMDBCommonUtil {
    /**
     * 排序方法
     *
     * @param list      数据list
     * @param sortField 排序字段
     * @param sortMode  排序方式
     * @param <T>
     */
    public static <T> void sortByField(List<Map<String, Object>> list, String sortField, int sortMode) {
        Pattern pattern = Pattern.compile("^-?(0|([1-9][0-9]*))(\\.[\\d]+)?$");
        Collections.sort(list, new Comparator<Map<String, Object>>() {
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                //对监控接口排序
                String param1 = strValueConvert(o1.get(sortField));
                String param2 = strValueConvert(o2.get(sortField));
                if (param1 != null) {
                    boolean isNumber = pattern.matcher(param1).matches();
                    if (isNumber) {
                        Double val1 = doubleValueConvert(param1);
                        Double val2 = doubleValueConvert(param2);
                        //升序
                        if (sortMode == 0) {
                            return val1.compareTo(val2);
                        } else {//降序
                            return val2.compareTo(val1);
                        }
                    } else {
                        //返回结果为字符串类型
                        Collator instace = Collator.getInstance(Locale.CHINA);
                        //升序
                        if (sortMode == 0) {
                            return instace.compare(param1, param2);
                        } else {//降序
                            return instace.compare(param2, param1);
                        }
                    }

                }
                return 0;
            }
        });
    }

    public static List<Map<String, Object>> filterByValueSubstring(List<Map<String, Object>> list, String substring) {
        return list.stream().filter(map -> mapContainsValueSubstring(map, substring)).collect(Collectors.toList());
    }

    public static boolean mapContainsValueSubstring(Map<String, Object> map, String substring) {
        for (Object value : map.values()) {
            if (value instanceof String && ((String) value).contains(substring)) {
                return true;
            }
        }
        return false;
    }







    public static <T> void sortListByField(List<T> list, String fieldPath, boolean ascending) {
        Collections.sort(list, new Comparator<T>() {
            @Override
            public int compare(T o1, T o2) {
                try {
                    String value1 = strValueConvert(getFieldValue(o1, fieldPath));
                    String value2 = strValueConvert(getFieldValue(o2, fieldPath));
                    if (value1 == null && value2 == null) {
                        return 0;
                    }
                    if (value1 == null) {
                        return ascending ? 1 : -1; // null 值排在最后
                    }
                    if (value2 == null) {
                        return ascending ? -1 : 1; // null 值排在最后
                    }
                    return ascending ? value1.compareTo(value2) : value2.compareTo(value1);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    private static Object getFieldValue(Object obj, String fieldPath) throws NoSuchFieldException, IllegalAccessException {
        String[] fields = fieldPath.split("\\.");
        Object value = obj;
        try{
            for (String fieldName : fields) {
                if (value == null) {
                    return null;
                }
                Field field = value.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                value = field.get(value);
            }
        }catch (Exception e){
            log.error("getFieldValue to fail::"+e);
            return null;
        }
        return value;
    }



    public static void gerAllChildIdList(List<TreeView> list, List<String> ids) {
        if (list == null) {
            return;
        }
        // 递归排序 childData
        for (TreeView item : list) {
            if(item instanceof TreeViewObject){
                TreeViewObject itemObj = (TreeViewObject)item;
                List<TreeView> childs = itemObj.getChilds();
                if(CollectionUtils.isEmpty(childs)){
                    ids.add(itemObj.getId());
                }
                gerAllChildIdList(childs,ids);
            }
        }
    }

    public static DataUniqueException validateUniqueDeviceByDeviceCode(List<InstanceInfo> paramList , ScanEngineService scanEngineService
            , InstanceServiceImpl instanceService , AssetsInterfaceMapper assetsInterfaceMapper
            ,MwEngineManageService mwEngineManageService) throws Exception{
        //检查并设置设备指纹信息
        List<Criteria> deviceCodeCriterias = CMDBScanEngineTool.setDeviceCode(paramList, scanEngineService ,mwEngineManageService);
        Map<String ,InstanceInfo> ipMap = new HashMap<>();
        Map<String ,InstanceInfo> deviceCodeMap = new HashMap<>();
        for(InstanceInfo instanceInfo : paramList){
            ipMap.put(instanceInfo.getInBandIp() ,instanceInfo);
            if(StringUtils.hasText(instanceInfo.getDeviceCode())){
                deviceCodeMap.put(instanceInfo.getDeviceCode() ,instanceInfo);
            }
        }

        if (null != deviceCodeCriterias && !deviceCodeCriterias.isEmpty()) {
            Query query = new Query(new Criteria().orOperator(deviceCodeCriterias));
            List<InstanceInfo> instanceInfos = instanceService.selectListByQuery(query);
            //已经存在了deviceCode相同的实例,则检查对应实例的网络接口ip是否重复
            if(null != instanceInfos && !instanceInfos.isEmpty()){
                List<Criteria> orCriterias = new ArrayList<>();
                for(InstanceInfo instanceInfo : instanceInfos){
                    List<Criteria> criteriaList = new ArrayList<>();
                    criteriaList.add(Criteria.where(CMDBTool.getFieldName(AssetsInterfaceDTO::getInstanceId)).is(instanceInfo.getId()));
                    InstanceInfo paramInstanceInfo = deviceCodeMap.get(instanceInfo.getDeviceCode());
                    criteriaList.add(Criteria.where(CMDBTool.getFieldName(AssetsInterfaceDTO::getIp)).is(paramInstanceInfo.getInBandIp()));
                    Criteria criteria = new Criteria().andOperator(criteriaList);
                    orCriterias.add(criteria);
                }
                query = new Query(new Criteria().orOperator(orCriterias));

                //一台网络设备存在多个不同的网络接口,用户可能使用不同的网络接口来添加资产
                //此时需要检查之前的网络设备中,是否包含当前添加资产的ip
                List<AssetsInterfaceDTO> assetsInterfaceDTOS = assetsInterfaceMapper.find(query);
                if(null != assetsInterfaceDTOS){
                    List<String> uniqueAlerts = new ArrayList<>();
                    String deviceCodeFieldName = CMDBTool.getFieldName(InstanceInfo::getDeviceCode);
                    for(AssetsInterfaceDTO assetsInterfaceDTO: assetsInterfaceDTOS){
                        InstanceInfo param = ipMap.get(assetsInterfaceDTO.getIp());
                        uniqueAlerts.add(param.getInstanceName() + "." + deviceCodeFieldName + InstanceServiceImpl.UniqueAlertSep + param.getDeviceCode());
                    }

                    if(!uniqueAlerts.isEmpty()){
                        return new DataUniqueException(new Object[]{uniqueAlerts});
                    }
                }
            }
        }
        return null;
    }

    public static boolean hasZabbix7Server(List<MwTPServerTable> mwTPServerTables){
        if(null == mwTPServerTables){
            return false;
        }

        boolean ret = false;
        for(MwTPServerTable mwTPServerTable: mwTPServerTables){
            if(mwTPServerTable.getMonitoringServerVersion().startsWith("7.")){
                ret = true;
            }
        }
        return ret;
    }

    public static <T> List<T> filterListByMap(List<T> list, Map<String, Object> map) {
        return list.stream()
                .filter(item -> matchesMap(item, map))
                .collect(Collectors.toList());
    }

    private static <T> boolean matchesMap(T item, Map<String, Object> map) {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String fieldName = entry.getKey();
            Object expectedValue = entry.getValue();

            try {
                Field field = item.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Object fieldValue = field.get(item);

                // 如果 Map 中的 value 是字符串，检查 fieldValue 是否包含 expectedValue
                if (fieldValue instanceof String && expectedValue instanceof String) {
                    if (!(strValueConvert(fieldValue)).toLowerCase().contains(strValueConvert(expectedValue).toLowerCase())) {
                        return false;
                    }
                }
                // 如果是其他类型，直接检查是否相等
                else if (!Objects.equals(fieldValue, expectedValue)) {
                    return false;
                }

            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

}
